﻿#include "MuYuEngine.h"

struct WICTranslate
{
	GUID wic;
	DXGI_FORMAT format;
};

static WICTranslate g_WICFormats[] =
{//WIC格式与DXGI像素格式的对应表，该表中的格式为被支持的格式
	{ GUID_WICPixelFormat128bppRGBAFloat,       DXGI_FORMAT_R32G32B32A32_FLOAT },

	{ GUID_WICPixelFormat64bppRGBAHalf,         DXGI_FORMAT_R16G16B16A16_FLOAT },
	{ GUID_WICPixelFormat64bppRGBA,             DXGI_FORMAT_R16G16B16A16_UNORM },

	{ GUID_WICPixelFormat32bppRGBA,             DXGI_FORMAT_R8G8B8A8_UNORM },
	{ GUID_WICPixelFormat32bppBGRA,             DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1
	{ GUID_WICPixelFormat32bppBGR,              DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1

	{ GUID_WICPixelFormat32bppRGBA1010102XR,    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1
	{ GUID_WICPixelFormat32bppRGBA1010102,      DXGI_FORMAT_R10G10B10A2_UNORM },

	{ GUID_WICPixelFormat16bppBGRA5551,         DXGI_FORMAT_B5G5R5A1_UNORM },
	{ GUID_WICPixelFormat16bppBGR565,           DXGI_FORMAT_B5G6R5_UNORM },

	{ GUID_WICPixelFormat32bppGrayFloat,        DXGI_FORMAT_R32_FLOAT },
	{ GUID_WICPixelFormat16bppGrayHalf,         DXGI_FORMAT_R16_FLOAT },
	{ GUID_WICPixelFormat16bppGray,             DXGI_FORMAT_R16_UNORM },
	{ GUID_WICPixelFormat8bppGray,              DXGI_FORMAT_R8_UNORM },

	{ GUID_WICPixelFormat8bppAlpha,             DXGI_FORMAT_A8_UNORM },
};

// WIC 像素格式转换表.
struct WICConvert
{
	GUID source;
	GUID target;
};

static WICConvert g_WICConvert[] =
{
	// 目标格式一定是最接近的被支持的格式
	{ GUID_WICPixelFormatBlackWhite,            GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM

	{ GUID_WICPixelFormat1bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat2bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat4bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat8bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM

	{ GUID_WICPixelFormat2bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
	{ GUID_WICPixelFormat4bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM

	{ GUID_WICPixelFormat16bppGrayFixedPoint,   GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
	{ GUID_WICPixelFormat32bppGrayFixedPoint,   GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT

	{ GUID_WICPixelFormat16bppBGR555,           GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM

	{ GUID_WICPixelFormat32bppBGR101010,        GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM

	{ GUID_WICPixelFormat24bppBGR,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat24bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat32bppPBGRA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat32bppPRGBA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM

	{ GUID_WICPixelFormat48bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat48bppBGR,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat64bppBGRA,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat64bppPRGBA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat64bppPBGRA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM

	{ GUID_WICPixelFormat48bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
	{ GUID_WICPixelFormat48bppBGRFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
	{ GUID_WICPixelFormat64bppRGBAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
	{ GUID_WICPixelFormat64bppBGRAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
	{ GUID_WICPixelFormat64bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
	{ GUID_WICPixelFormat48bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
	{ GUID_WICPixelFormat64bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT

	{ GUID_WICPixelFormat128bppPRGBAFloat,      GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
	{ GUID_WICPixelFormat128bppRGBFloat,        GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
	{ GUID_WICPixelFormat128bppRGBAFixedPoint,  GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
	{ GUID_WICPixelFormat128bppRGBFixedPoint,   GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
	{ GUID_WICPixelFormat32bppRGBE,             GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT

	{ GUID_WICPixelFormat32bppCMYK,             GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat64bppCMYK,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat40bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat80bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM

	{ GUID_WICPixelFormat32bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
	{ GUID_WICPixelFormat64bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
	{ GUID_WICPixelFormat64bppPRGBAHalf,        GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
};

bool GetTargetPixelFormat(const GUID* pSourceFormat, GUID* pTargetFormat)
{//查表确定兼容的最接近格式是哪个
	*pTargetFormat = *pSourceFormat;
	for (size_t i = 0; i < _countof(g_WICConvert); ++i)
	{
		if (InlineIsEqualGUID(g_WICConvert[i].source, *pSourceFormat))
		{
			*pTargetFormat = g_WICConvert[i].target;
			return true;
		}
	}
	return false;
}

DXGI_FORMAT GetDXGIFormatFromPixelFormat(const GUID* pPixelFormat)
{//查表确定最终对应的DXGI格式是哪一个
	for (size_t i = 0; i < _countof(g_WICFormats); ++i)
	{
		if (InlineIsEqualGUID(g_WICFormats[i].wic, *pPixelFormat))
		{
			return g_WICFormats[i].format;
		}
	}
	return DXGI_FORMAT_UNKNOWN;
}

MuYuEngine::MuYuEngine(UINT width, UINT height, std::wstring name) :
	RenderUnit(width, height, name),
	nFrameIndex(0),
	m_viewport(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height)),
	m_scissorRect(0, 0, static_cast<LONG>(width), static_cast<LONG>(height)),
	nRTVDescriptorSize(0)
{
}

void MuYuEngine::OnInit()
{
	LoadPipeline();
	LoadTexture();
	LoadAssets();
}

// Load the rendering pipeline dependencies.
void MuYuEngine::LoadPipeline()
{
	MuYu_USEPRINTF();
	//打开窗口程序的命令行窗口支持
	AllocConsole();
	//打开系统的DX12的调试支持
	{
#if defined(_DEBUG)
		if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(pID3DDebugLayer1.GetAddressOf()))))
		{
			pID3DDebugLayer1->EnableDebugLayer();
			dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
		}
#endif
	}

	//创建DXGI-FACTORY对象
	{
		MuYu_THROW_IF_FAILED(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(pIDXGIFactory5.GetAddressOf())));
		MuYu_THROW_IF_FAILED(pIDXGIFactory5->MakeWindowAssociation(MuYuWnd::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
	}

	//枚举适配器，创建3D设备对象
	{
		auto d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0;
		D3D12_FEATURE_DATA_ARCHITECTURE stArchitecture = {};
		for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pIDXGIFactory5->EnumAdapters1(adapterIndex, pIAdapter1.GetAddressOf()); ++adapterIndex)
		{
			DXGI_ADAPTER_DESC1 desc = {};
			pIAdapter1->GetDesc1(&desc);
			if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
			{
				continue;//跳过虚拟适配器
			}

			MuYu_PRINTF(_T("显卡[%d]-\"%s\":独占显存[%dMB]、独占内存[%dMB]、共享内存[%dMB] "),
				adapterIndex,
				desc.Description,
				desc.DedicatedVideoMemory / (1024 * 1024),
				desc.DedicatedSystemMemory / (1024 * 1024),
				desc.SharedSystemMemory / (1024 * 1024));

			//创建设备，并检测架构
			MuYu_THROW_IF_FAILED(D3D12CreateDevice(pIAdapter1.Get(), d3dFeatureLevel, IID_PPV_ARGS(pID3DDevice4.GetAddressOf())));
			MuYu_THROW_IF_FAILED(pID3DDevice4->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &stArchitecture, sizeof(stArchitecture)));
			if (stArchitecture.UMA)
			{
				if (stArchitecture.CacheCoherentUMA)
				{
					MuYu_PRINTF(_T("架构为（CC-UMA）"));
				}
				else
				{
					MuYu_PRINTF(_T("架构为（UMA）"));
				}
			}
			else
			{
				MuYu_PRINTF(_T("架构为（NUMA）"));
			}
			if (stArchitecture.TileBasedRenderer)
			{
				MuYu_PRINTF(_T("支持Tile-based方式渲染"));
			}
			pID3DDevice4.Reset();
			MuYu_PRINTF(_T("\n"));
		}
		MuYu_THROW_IF_FAILED(D3D12CreateDevice(pIAdapter1.Get(), d3dFeatureLevel, IID_PPV_ARGS(pID3DDevice4.GetAddressOf())));
	}

	//创建直接命令队列
	{
		D3D12_COMMAND_QUEUE_DESC stQueueDesc = {};
		stQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateCommandQueue(&stQueueDesc, IID_PPV_ARGS(pICommandQueue.GetAddressOf())));
	}

	//创建交换链
	{
		DXGI_SWAP_CHAIN_DESC1 stSwapChainDesc = {};
		stSwapChainDesc.BufferCount = nFrameBackBuffCount;
		stSwapChainDesc.Width = GetWidth();
		stSwapChainDesc.Height = GetHeight();
		stSwapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		stSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		stSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		stSwapChainDesc.SampleDesc.Count = 1;
		MuYu_THROW_IF_FAILED(pIDXGIFactory5->CreateSwapChainForHwnd(
			pICommandQueue.Get(),
			MuYuWnd::GetHwnd(),
			&stSwapChainDesc,
			nullptr,
			nullptr,
			&pISwapChain1));
		MuYu_THROW_IF_FAILED(pISwapChain1.As(&pISwapChain3));
		nFrameIndex = pISwapChain3->GetCurrentBackBufferIndex();
	}

	//创建RTV(渲染目标视图)描述符堆
	{
		D3D12_DESCRIPTOR_HEAP_DESC stRTVHeapDesc = {};
		stRTVHeapDesc.NumDescriptors = nFrameBackBuffCount;
		stRTVHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
		stRTVHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateDescriptorHeap(&stRTVHeapDesc, IID_PPV_ARGS(pIRTVHeap.GetAddressOf())));

		nRTVDescriptorSize = pID3DDevice4->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
		CD3DX12_CPU_DESCRIPTOR_HANDLE stRTVHandle(pIRTVHeap->GetCPUDescriptorHandleForHeapStart());
		for (UINT i = 0; i < nFrameBackBuffCount; ++i)
		{
			MuYu_THROW_IF_FAILED(pISwapChain3->GetBuffer(i, IID_PPV_ARGS(pIARenderTargets[i].GetAddressOf())));
			pID3DDevice4->CreateRenderTargetView(pIARenderTargets[i].Get(), nullptr, stRTVHandle);
			stRTVHandle.Offset(1, nRTVDescriptorSize);
		}
	}

	//创建SRV堆
	{
		D3D12_DESCRIPTOR_HEAP_DESC stSRVHeapDesc = {};
		stSRVHeapDesc.NumDescriptors = 2; //1 SRV + 1 CBV
		stSRVHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
		stSRVHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateDescriptorHeap(&stSRVHeapDesc, IID_PPV_ARGS(pISRVHeap.GetAddressOf())));
	}

	//创建采样器堆
	{
		D3D12_DESCRIPTOR_HEAP_DESC stSamplerHeapDesc = {};
		stSamplerHeapDesc.NumDescriptors = nSampleMaxCnt;
		stSamplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
		stSamplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateDescriptorHeap(&stSamplerHeapDesc, IID_PPV_ARGS(&pISamplerDescriptorHeap)));

		nSamplerDescriptorSize = pID3DDevice4->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
	}

	//创建根描述符
	{
		D3D12_FEATURE_DATA_ROOT_SIGNATURE stFeatureData = {};
		stFeatureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;
		if (FAILED(pID3DDevice4->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &stFeatureData, sizeof(stFeatureData))))
		{
			stFeatureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;
		}
		CD3DX12_DESCRIPTOR_RANGE1 stDSPRanges[3];
		stDSPRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);
		stDSPRanges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
		stDSPRanges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);


		CD3DX12_ROOT_PARAMETER1 stRootParameters[3];
		stRootParameters[0].InitAsDescriptorTable(1, &stDSPRanges[0], D3D12_SHADER_VISIBILITY_PIXEL);
		stRootParameters[1].InitAsDescriptorTable(1, &stDSPRanges[1], D3D12_SHADER_VISIBILITY_ALL); //CBV是所有Shader可见
		stRootParameters[2].InitAsDescriptorTable(1, &stDSPRanges[2], D3D12_SHADER_VISIBILITY_PIXEL);

		//D3D12_STATIC_SAMPLER_DESC stSamplerDesc = {};
		//stSamplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
		//stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		//stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		//stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		//stSamplerDesc.MipLODBias = 0;
		//stSamplerDesc.MaxAnisotropy = 0;
		//stSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
		//stSamplerDesc.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
		//stSamplerDesc.MinLOD = 0.0f;
		//stSamplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
		//stSamplerDesc.ShaderRegister = 0;
		//stSamplerDesc.RegisterSpace = 0;
		//stSamplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;

		CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC stRootSignatureDesc = {};
		//stRootSignatureDesc.Init_1_1(_countof(stRootParameters), stRootParameters,
		//	1,
		//	&stSamplerDesc,
		//	D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
		stRootSignatureDesc.Init_1_1(_countof(stRootParameters), stRootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

		ComPtr<ID3DBlob> pISignatureBlob;
		ComPtr<ID3DBlob> pIErrorBlob;
		MuYu_THROW_IF_FAILED(D3DX12SerializeVersionedRootSignature(&stRootSignatureDesc
			, stFeatureData.HighestVersion
			, &pISignatureBlob
			, &pIErrorBlob));
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateRootSignature(0
			, pISignatureBlob->GetBufferPointer()
			, pISignatureBlob->GetBufferSize()
			, IID_PPV_ARGS(&pIRootSignature)));
	}

	//编译SHADER
	{
#if defined(_DEBUG)
		UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
		UINT compileFlags = 0;
#endif

		compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;

		TCHAR pszShaderFileName[] = _T("shaders.hlsl");
		MuYu_THROW_IF_FAILED(D3DCompileFromFile(pszShaderFileName, nullptr, nullptr
			, "VSMain", "vs_5_0", compileFlags, 0, &pIBlobVertexShader, nullptr));
		MuYu_THROW_IF_FAILED(D3DCompileFromFile(pszShaderFileName, nullptr, nullptr
			, "PSMain", "ps_5_0", compileFlags, 0, &pIBlobPixelShader, nullptr));
		stInputElementDescs[0] = { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
		stInputElementDescs[1] = { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
		stInputElementDescs[2] = { "NORMAL", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 20, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
	}

	//创建PSO
	{
		D3D12_GRAPHICS_PIPELINE_STATE_DESC stPSODesc = {};
		stPSODesc.InputLayout = { stInputElementDescs, _countof(stInputElementDescs) };
		stPSODesc.pRootSignature = pIRootSignature.Get();
		stPSODesc.VS = CD3DX12_SHADER_BYTECODE(pIBlobVertexShader.Get());
		stPSODesc.PS = CD3DX12_SHADER_BYTECODE(pIBlobPixelShader.Get());
		stPSODesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
		stPSODesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
		stPSODesc.DepthStencilState.DepthEnable = FALSE;
		stPSODesc.DepthStencilState.StencilEnable = FALSE;
		stPSODesc.SampleMask = UINT_MAX;
		stPSODesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
		stPSODesc.NumRenderTargets = 1;
		stPSODesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
		stPSODesc.SampleDesc.Count = 1;

		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateGraphicsPipelineState(&stPSODesc, IID_PPV_ARGS(pIPipelineState.GetAddressOf())));
	}

	//创建命令分配器
	{
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(pICommandAllocator.GetAddressOf())));
	}

	//创建命令列表
	{
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pICommandAllocator.Get(), pIPipelineState.Get(), IID_PPV_ARGS(pICommandList.GetAddressOf())));
	}
}

// Load the sample assets.
void MuYuEngine::LoadAssets()
{
	//创建纹理堆和纹理资源
	{
		//纹理堆
		D3D12_HEAP_DESC stTextureHeapDesc = {};
		stTextureHeapDesc.SizeInBytes = MuYu_UPPER(2 * nPicRowPitch * nTextureH, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
		stTextureHeapDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
		stTextureHeapDesc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
		stTextureHeapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
		stTextureHeapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
		stTextureHeapDesc.Flags = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_BUFFERS;
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateHeap(&stTextureHeapDesc, IID_PPV_ARGS(pITextureHeap.GetAddressOf())));

		D3D12_RESOURCE_DESC stTextureDesc = {};
		stTextureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
		stTextureDesc.MipLevels = 1;
		stTextureDesc.Format = stTextureFormat; //DXGI_FORMAT_R8G8B8A8_UNORM;
		stTextureDesc.Width = nTextureW;
		stTextureDesc.Height = nTextureH;
		stTextureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
		stTextureDesc.DepthOrArraySize = 1;
		stTextureDesc.SampleDesc.Count = 1;
		stTextureDesc.SampleDesc.Quality = 0;

		////创建默认堆上的资源，类型是Texture2D，GPU对默认堆资源的访问速度是最快的
		////因为纹理资源一般是不易变的资源，所以我们通常使用上传堆复制到默认堆中
		////在传统的D3D11及以前的D3D接口中，这些过程都被封装了，我们只能指定创建时的类型为默认堆 
		//MuYu_THROW_IF_FAILED(pID3DDevice4->CreateCommittedResource(
		//	&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT)
		//	, D3D12_HEAP_FLAG_NONE
		//	, &stTextureDesc				//可以使用CD3DX12_RESOURCE_DESC::Tex2D来简化结构体的初始化
		//	, D3D12_RESOURCE_STATE_COPY_DEST
		//	, nullptr
		//	, IID_PPV_ARGS(&pITexcute)));
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreatePlacedResource(
			pITextureHeap.Get(),
			0,
			&stTextureDesc,
			D3D12_RESOURCE_STATE_COPY_DEST,
			nullptr,
			IID_PPV_ARGS(pITexcute.GetAddressOf())));



		//获取上传堆资源缓冲的大小，这个尺寸通常大于实际图片的尺寸
		const UINT64 n64UploadBufferSize = GetRequiredIntermediateSize(pITexcute.Get(), 0, 1);

		//// 创建用于上传纹理的资源,注意其类型是Buffer
		//// 上传堆对于GPU访问来说性能是很差的，
		//// 所以对于几乎不变的数据尤其像纹理都是
		//// 通过它来上传至GPU访问更高效的默认堆中
		//MuYu_THROW_IF_FAILED(pID3DDevice4->CreateCommittedResource(
		//	&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
		//	D3D12_HEAP_FLAG_NONE,
		//	&CD3DX12_RESOURCE_DESC::Buffer(n64UploadBufferSize),
		//	D3D12_RESOURCE_STATE_GENERIC_READ,
		//	nullptr,
		//	IID_PPV_ARGS(&pITextureUpload)));

		D3D12_HEAP_DESC stUploadHeapDesc = {};
		stUploadHeapDesc.SizeInBytes = MuYu_UPPER(2 * n64UploadBufferSize, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
		stUploadHeapDesc.Alignment = 0;
		stUploadHeapDesc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD;
		stUploadHeapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
		stUploadHeapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
		stUploadHeapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;

		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateHeap(&stUploadHeapDesc, IID_PPV_ARGS(pIUploadHeap.GetAddressOf())));

		MuYu_THROW_IF_FAILED(pID3DDevice4->CreatePlacedResource(pIUploadHeap.Get(),
			0,
			&CD3DX12_RESOURCE_DESC::Buffer(n64UploadBufferSize),
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(pITextureUpload.GetAddressOf())));

		Vertex stTriangleVertices[] =
		{
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 0.0f * fTCMax}, {0.0f,  0.0f, -1.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  0.0f, -1.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax}, {0.0f,  0.0f, -1.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax}, {0.0f,  0.0f, -1.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f, 0.0f, -1.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 1.0f * fTCMax},  {0.0f,  0.0f, -1.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 0.0f * fTCMax},  {1.0f,  0.0f,  0.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {1.0f,  0.0f,  0.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {1.0f,  0.0f,  0.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {1.0f,  0.0f,  0.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {1.0f,  0.0f,  0.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 1.0f * fTCMax},  {1.0f,  0.0f,  0.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  0.0f,  1.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  0.0f,  1.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax}, {0.0f,  0.0f,  1.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {0.0f,  0.0f,  1.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  0.0f,  1.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 1.0f * fTCMax},  {0.0f,  0.0f,  1.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 0.0f * fTCMax}, {-1.0f,  0.0f,  0.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax}, {-1.0f,  0.0f,  0.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax}, {-1.0f,  0.0f,  0.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax}, {-1.0f,  0.0f,  0.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax}, {-1.0f,  0.0f,  0.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 1.0f * fTCMax}, {-1.0f,  0.0f,  0.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  1.0f,  0.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  1.0f,  0.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {0.0f,  1.0f,  0.0f} },
			{ {-1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {0.0f,  1.0f,  0.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f,  1.0f,  0.0f} },
			{ {1.0f * fBoxSize,  1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 1.0f * fTCMax},  {0.0f,  1.0f,  0.0f }},
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {0.0f * fTCMax, 0.0f * fTCMax},  {0.0f, -1.0f,  0.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f, -1.0f,  0.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {0.0f, -1.0f,  0.0f} },
			{ {-1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {0.0f * fTCMax, 1.0f * fTCMax},  {0.0f, -1.0f,  0.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize, -1.0f * fBoxSize}, {1.0f * fTCMax, 0.0f * fTCMax},  {0.0f, -1.0f,  0.0f} },
			{ {1.0f * fBoxSize, -1.0f * fBoxSize,  1.0f * fBoxSize}, {1.0f * fTCMax, 1.0f * fTCMax},  {0.0f, -1.0f,  0.0f} },
		};

		const UINT nVertexBufferSize = sizeof(stTriangleVertices);
		//MuYu_THROW_IF_FAILED(pID3DDevice4->CreateCommittedResource(
		//	&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
		//	D3D12_HEAP_FLAG_NONE,
		//	&CD3DX12_RESOURCE_DESC::Buffer(nVertexBufferSize),
		//	D3D12_RESOURCE_STATE_GENERIC_READ,
		//	nullptr,
		//	IID_PPV_ARGS(&pIVertexBuffer)));

		n64BufferOffset = MuYu_UPPER(n64UploadBufferSize, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);

		MuYu_THROW_IF_FAILED(pID3DDevice4->CreatePlacedResource(
			pIUploadHeap.Get(),
			n64BufferOffset,
			&CD3DX12_RESOURCE_DESC::Buffer(nVertexBufferSize),
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(pIVertexBuffer.GetAddressOf())));

		UINT8* pVertexDataBegin = nullptr;
		CD3DX12_RANGE stReadRange(0, 0);		// We do not intend to read from this resource on the CPU.
		MuYu_THROW_IF_FAILED(pIVertexBuffer->Map(0, &stReadRange, reinterpret_cast<void**>(&pVertexDataBegin)));
		memcpy(pVertexDataBegin, stTriangleVertices, sizeof(stTriangleVertices));
		pIVertexBuffer->Unmap(0, nullptr);

		stVertexBufferView.BufferLocation = pIVertexBuffer->GetGPUVirtualAddress();
		stVertexBufferView.StrideInBytes = sizeof(Vertex);
		stVertexBufferView.SizeInBytes = nVertexBufferSize;

		UINT32 pBoxIndices[] //立方体索引数组
			= {
			0,1,2,
			3,4,5,

			6,7,8,
			9,10,11,

			12,13,14,
			15,16,17,

			18,19,20,
			21,22,23,

			24,25,26,
			27,28,29,

			30,31,32,
			33,34,35,
		};

		const UINT nszIndexBuffer = sizeof(pBoxIndices);
		mBoxIndicesCount = _countof(pBoxIndices);

		//计算边界对齐的正确的偏移位置
		n64BufferOffset = MuYu_UPPER(n64BufferOffset + nVertexBufferSize, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);

		MuYu_THROW_IF_FAILED(pID3DDevice4->CreatePlacedResource(
			pIUploadHeap.Get()
			, n64BufferOffset
			, &CD3DX12_RESOURCE_DESC::Buffer(nszIndexBuffer)
			, D3D12_RESOURCE_STATE_GENERIC_READ
			, nullptr
			, IID_PPV_ARGS(&pIIndexBuffer)));

		UINT8* pIndexDataBegin = nullptr;
		//CD3DX12_RANGE stReadRange_index(0, 0);
		MuYu_THROW_IF_FAILED(pIIndexBuffer->Map(0, &stReadRange, reinterpret_cast<void**>(&pIndexDataBegin)));
		memcpy(pIndexDataBegin, pBoxIndices, nszIndexBuffer);
		pIIndexBuffer->Unmap(0, nullptr);

		stIndexBufferView.BufferLocation = pIIndexBuffer->GetGPUVirtualAddress();
		stIndexBufferView.Format = DXGI_FORMAT_R32_UINT;
		stIndexBufferView.SizeInBytes = nszIndexBuffer;

		//按照资源缓冲大小来分配实际图片数据存储的内存大小
		void* pbPicData = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, n64UploadBufferSize);
		if (nullptr == pbPicData)
		{
			throw MuYuException(HRESULT_FROM_WIN32(GetLastError()));
		}

		//从图片中读取出数据
		MuYu_THROW_IF_FAILED(pIBMP->CopyPixels(nullptr
			, nPicRowPitch
			, static_cast<UINT>(nPicRowPitch * nTextureH)   //注意这里才是图片数据真实的大小，这个值通常小于缓冲的大小
			, reinterpret_cast<BYTE*>(pbPicData)));

		//获取向上传堆拷贝纹理数据的一些纹理转换尺寸信息
		//对于复杂的DDS纹理这是非常必要的过程
		UINT64 n64RequiredSize = 0u;
		UINT   nNumSubresources = 1u;  //我们只有一副图片，即子资源个数为1
		D3D12_PLACED_SUBRESOURCE_FOOTPRINT stTxtLayouts = {};
		UINT64 n64TextureRowSizes = 0u;
		UINT   nTextureRowNum = 0u;

		D3D12_RESOURCE_DESC stDestDesc = pITexcute->GetDesc();

		pID3DDevice4->GetCopyableFootprints(&stDestDesc
			, 0
			, nNumSubresources
			, 0
			, &stTxtLayouts
			, &nTextureRowNum
			, &n64TextureRowSizes
			, &n64RequiredSize);

		//因为上传堆实际就是CPU传递数据到GPU的中介
		//所以我们可以使用熟悉的Map方法将它先映射到CPU内存地址中
		//然后我们按行将数据复制到上传堆中
		//需要注意的是之所以按行拷贝是因为GPU资源的行大小
		//与实际图片的行大小是有差异的,二者的内存边界对齐要求是不一样的
		BYTE* pData = nullptr;
		MuYu_THROW_IF_FAILED(pITextureUpload->Map(0, NULL, reinterpret_cast<void**>(&pData)));

		BYTE* pDestSlice = reinterpret_cast<BYTE*>(pData) + stTxtLayouts.Offset;
		const BYTE* pSrcSlice = reinterpret_cast<const BYTE*>(pbPicData);
		for (UINT y = 0; y < nTextureRowNum; ++y)
		{
			memcpy(pDestSlice + static_cast<SIZE_T>(stTxtLayouts.Footprint.RowPitch) * y
				, pSrcSlice + static_cast<SIZE_T>(nPicRowPitch) * y
				, nPicRowPitch);
		}
		//取消映射 对于易变的数据如每帧的变换矩阵等数据，可以撒懒不用Unmap了，
		//让它常驻内存,以提高整体性能，因为每次Map和Unmap是很耗时的操作
		//因为现在起码都是64位系统和应用了，地址空间是足够的，被长期占用不会影响什么
		pITextureUpload->Unmap(0, NULL);

		//释放图片数据，做一个干净的程序员
		::HeapFree(::GetProcessHeap(), 0, pbPicData);

		//向命令队列发出从上传堆复制纹理数据到默认堆的命令
		CD3DX12_TEXTURE_COPY_LOCATION Dst(pITexcute.Get(), 0);
		CD3DX12_TEXTURE_COPY_LOCATION Src(pITextureUpload.Get(), stTxtLayouts);
		pICommandList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);

		//设置一个资源屏障，同步并确认复制操作完成
		//直接使用结构体然后调用的形式
		D3D12_RESOURCE_BARRIER stResBar = {};
		stResBar.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
		stResBar.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
		stResBar.Transition.pResource = pITexcute.Get();
		stResBar.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
		stResBar.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
		stResBar.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;

		pICommandList->ResourceBarrier(1, &stResBar);

		//创建CBV
		{
			n64BufferOffset = MuYu_UPPER(n64BufferOffset + nszIndexBuffer, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
			// 创建常量缓冲 注意缓冲尺寸设置为256边界对齐大小
			MuYu_THROW_IF_FAILED(pID3DDevice4->CreatePlacedResource(
				pIUploadHeap.Get()
				, n64BufferOffset
				, &CD3DX12_RESOURCE_DESC::Buffer(szMVPBuffer)
				, D3D12_RESOURCE_STATE_GENERIC_READ
				, nullptr
				, IID_PPV_ARGS(&pICBVUpload)));

			// Map 之后就不再Unmap了 直接复制数据进去 这样每帧都不用map-copy-unmap浪费时间了
			MuYu_THROW_IF_FAILED(pICBVUpload->Map(0, nullptr, reinterpret_cast<void**>(&pMVPBuffer)));
		}

		//创建SRV描述符
		{
			D3D12_SHADER_RESOURCE_VIEW_DESC stSRVDesc = {};
			stSRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
			stSRVDesc.Format = stTextureDesc.Format;
			stSRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
			stSRVDesc.Texture2D.MipLevels = 1;
			pID3DDevice4->CreateShaderResourceView(pITexcute.Get(), &stSRVDesc, pISRVHeap->GetCPUDescriptorHandleForHeapStart());
		}

		//创建CBV描述符
		{
			D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
			cbvDesc.BufferLocation = pICBVUpload->GetGPUVirtualAddress();
			cbvDesc.SizeInBytes = static_cast<UINT>(szMVPBuffer);

			CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(pISRVHeap->GetCPUDescriptorHandleForHeapStart()
				, 1
				, pID3DDevice4->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));

			pID3DDevice4->CreateConstantBufferView(&cbvDesc, cbvSrvHandle);
		}

		//创建采样器描述符
		{
			CD3DX12_CPU_DESCRIPTOR_HANDLE hSamplerHeap(pISamplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
			D3D12_SAMPLER_DESC stSamplerDesc = {};
			stSamplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;

			stSamplerDesc.MinLOD = 0;
			stSamplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
			stSamplerDesc.MipLODBias = 0.0f;
			stSamplerDesc.MaxAnisotropy = 1;
			stSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;

			// Sampler 1
			stSamplerDesc.BorderColor[0] = 1.0f;
			stSamplerDesc.BorderColor[1] = 0.0f;
			stSamplerDesc.BorderColor[2] = 1.0f;
			stSamplerDesc.BorderColor[3] = 1.0f;
			stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
			stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
			stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
			pID3DDevice4->CreateSampler(&stSamplerDesc, hSamplerHeap);

			hSamplerHeap.Offset(nSamplerDescriptorSize);

			// Sampler 2
			stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
			stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
			stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
			pID3DDevice4->CreateSampler(&stSamplerDesc, hSamplerHeap);

			hSamplerHeap.Offset(nSamplerDescriptorSize);

			// Sampler 3
			stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
			stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
			stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
			pID3DDevice4->CreateSampler(&stSamplerDesc, hSamplerHeap);

			hSamplerHeap.Offset(nSamplerDescriptorSize);

			// Sampler 4
			stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
			stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
			stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
			pID3DDevice4->CreateSampler(&stSamplerDesc, hSamplerHeap);

			hSamplerHeap.Offset(nSamplerDescriptorSize);

			// Sampler 5
			stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;
			stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;
			stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;
			pID3DDevice4->CreateSampler(&stSamplerDesc, hSamplerHeap);
		}

		// 执行命令列表并等待纹理资源上传完成，这一步是必须的
		MuYu_THROW_IF_FAILED(pICommandList->Close());
		ID3D12CommandList* ppCommandList[] = { pICommandList.Get() };
		pICommandQueue->ExecuteCommandLists(_countof(ppCommandList), ppCommandList);
	}

	//创建围栏
	{
		// 17、创建一个同步对象——围栏，用于等待渲染完成，因为现在Draw Call是异步的了
		MuYu_THROW_IF_FAILED(pID3DDevice4->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pIFence)));
		n64FenceValue = 1;
		// 18、创建一个Event同步对象，用于等待围栏事件通知
		hFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
		if (hFenceEvent == nullptr)
		{
			MuYu_THROW_IF_FAILED(HRESULT_FROM_WIN32(GetLastError()));
		}
		// 19、等待纹理资源正式复制完成先
		const UINT64 fence = n64FenceValue;
		MuYu_THROW_IF_FAILED(pICommandQueue->Signal(pIFence.Get(), fence));
		n64FenceValue++;
		if (pIFence->GetCompletedValue() < fence)
		{
			MuYu_THROW_IF_FAILED(pIFence->SetEventOnCompletion(fence, hFenceEvent));
			WaitForSingleObject(hFenceEvent, INFINITE);
		}
	}

	//命令分配器先Reset一下，刚才已经执行过了一个复制纹理的命令
	MuYu_THROW_IF_FAILED(pICommandAllocator->Reset());
	//Reset命令列表，并重新指定命令分配器和PSO对象
	MuYu_THROW_IF_FAILED(pICommandList->Reset(pICommandAllocator.Get(), pIPipelineState.Get()));
}

// Update frame-based values.
void MuYuEngine::OnUpdate()
{
	n64tmCurrent = ::GetTickCount64();
	//计算旋转的角度：旋转角度(弧度) = 时间(秒) * 角速度(弧度/秒)
	//下面这句代码相当于经典游戏消息循环中的OnUpdate函数中需要做的事情
	dModelRotationYAngle += ((n64tmCurrent - n64tmFrameStart) / 1000.0f) * fPalstance;

	n64tmFrameStart = n64tmCurrent;

	//旋转角度是2PI周期的倍数，去掉周期数，只留下相对0弧度开始的小于2PI的弧度即可
	if (dModelRotationYAngle > XM_2PI)
	{
		dModelRotationYAngle = fmod(dModelRotationYAngle, XM_2PI);
	}

	//模型矩阵 model
	XMMATRIX xmRot = XMMatrixRotationY(static_cast<float>(dModelRotationYAngle));

	//计算 模型矩阵 model * 视矩阵 view
	XMMATRIX xmMVP = XMMatrixMultiply(xmRot, XMMatrixLookAtLH(Eye, At, Up));

	//投影矩阵 projection
	xmMVP = XMMatrixMultiply(xmMVP, (XMMatrixPerspectiveFovLH(XM_PIDIV4, (FLOAT)GetWidth() / (FLOAT)GetHeight(), 0.1f, 1000.0f)));

	XMStoreFloat4x4(&pMVPBuffer->m_MVP, xmMVP);
}

// Render the scene.
void MuYuEngine::OnRender()
{
	// Record all the commands we need to render the scene into the command list.
	PopulateCommandList();

	// Execute the command list.
	ID3D12CommandList* ppCommandList[] = { pICommandList.Get() };
	pICommandQueue->ExecuteCommandLists(_countof(ppCommandList), ppCommandList);

	// Present the frame.
	MuYu_THROW_IF_FAILED(pISwapChain3->Present(1, 0));

	WaitForPreviousFrame();
}

void MuYuEngine::OnDestroy()
{
	// Ensure that the GPU is no longer referencing resources that are about to be
	// cleaned up by the destructor.
	//WaitForPreviousFrame();
	//释放围栏事件
	CloseHandle(hFenceEvent);
	//释放命令环境
	FreeConsole();
}

void MuYuEngine::PopulateCommandList()
{
	pICommandList->SetGraphicsRootSignature(pIRootSignature.Get());
	ID3D12DescriptorHeap* ppHeaps[] = { pISRVHeap.Get(),pISamplerDescriptorHeap.Get() };
	pICommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);

	//SRV
	pICommandList->SetGraphicsRootDescriptorTable(0, pISRVHeap->GetGPUDescriptorHandleForHeapStart());

	CD3DX12_GPU_DESCRIPTOR_HANDLE stGPUCBVHandle(pISRVHeap->GetGPUDescriptorHandleForHeapStart()
		, 1
		, pID3DDevice4->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));

	//CBV
	pICommandList->SetGraphicsRootDescriptorTable(1, stGPUCBVHandle);

	//采样器
	CD3DX12_GPU_DESCRIPTOR_HANDLE hGPUSampler(pISamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart(),
		nCurrentSamplerNO,
		nSamplerDescriptorSize);
	pICommandList->SetGraphicsRootDescriptorTable(2, hGPUSampler);


	pICommandList->RSSetViewports(1, &m_viewport);
	pICommandList->RSSetScissorRects(1, &m_scissorRect);

	// 通过资源屏障判定后缓冲已经切换完毕可以开始渲染了
	pICommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pIARenderTargets[nFrameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

	CD3DX12_CPU_DESCRIPTOR_HANDLE stRTVHandle(pIRTVHeap->GetCPUDescriptorHandleForHeapStart(), nFrameIndex, nRTVDescriptorSize);
	//设置渲染目标
	pICommandList->OMSetRenderTargets(1, &stRTVHandle, FALSE, nullptr);

	// 继续记录命令，并真正开始新一帧的渲染
	const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
	pICommandList->ClearRenderTargetView(stRTVHandle, clearColor, 0, nullptr);
	pICommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);//(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
	pICommandList->IASetVertexBuffers(0, 1, &stVertexBufferView);
	pICommandList->IASetIndexBuffer(&stIndexBufferView);

	//DRAW CALL
	pICommandList->DrawIndexedInstanced(mBoxIndicesCount, 1, 0, 0, 0);

	//---------------------------------------------------------------------------------------------
	//又一个资源屏障，用于确定渲染已经结束可以提交画面去显示了
	pICommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pIARenderTargets[nFrameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
	//关闭命令列表，可以去执行了
	MuYu_THROW_IF_FAILED(pICommandList->Close());
}

void MuYuEngine::WaitForPreviousFrame()
{
	// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
	// This is code implemented as such for simplicity. The D3D12HelloFrameBuffering
	// sample illustrates how to use fences for efficient resource usage and to
	// maximize GPU utilization.

	// Signal and increment the fence value.
	const UINT64 fence = n64FenceValue;
	MuYu_THROW_IF_FAILED(pICommandQueue->Signal(pIFence.Get(), fence));
	n64FenceValue++;

	// Wait until the previous frame is finished.
	if (pIFence->GetCompletedValue() < fence)
	{
		MuYu_THROW_IF_FAILED(pIFence->SetEventOnCompletion(fence, hFenceEvent));
		WaitForSingleObject(hFenceEvent, INFINITE);
	}
	//获取新的后缓冲序号，因为Present真正完成时后缓冲的序号就更新了
	nFrameIndex = pISwapChain3->GetCurrentBackBufferIndex();

	//命令分配器先Reset一下
	MuYu_THROW_IF_FAILED(pICommandAllocator->Reset());
	//Reset命令列表，并重新指定命令分配器和PSO对象
	MuYu_THROW_IF_FAILED(pICommandList->Reset(pICommandAllocator.Get(), pIPipelineState.Get()));

}

void MuYuEngine::LoadTexture() {
	// 16、使用WIC创建并加载一个2D纹理
		//使用纯COM方式创建WIC类厂对象，也是调用WIC第一步要做的事情
	MuYu_THROW_IF_FAILED(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIWICFactory)));

	//使用WIC类厂对象接口加载纹理图片，并得到一个WIC解码器对象接口，图片信息就在这个接口代表的对象中了
	auto pszTexcuteFileName = _T("../../demo4.jpg");//"D:\\0-U2018-DEMO\\monster-rp\\demo4.jpg"
	MuYu_THROW_IF_FAILED(pIWICFactory->CreateDecoderFromFilename(
		pszTexcuteFileName,              // 文件名
		NULL,                            // 不指定解码器，使用默认
		GENERIC_READ,                    // 访问权限
		WICDecodeMetadataCacheOnDemand,  // 若需要就缓冲数据 
		&pIWICDecoder                    // 解码器对象
	));

	// 获取第一帧图片(因为GIF等格式文件可能会有多帧图片，其他的格式一般只有一帧图片)
	// 实际解析出来的往往是位图格式数据
	MuYu_THROW_IF_FAILED(pIWICDecoder->GetFrame(0, &pIWICFrame));

	WICPixelFormatGUID wpf = {};
	//获取WIC图片格式
	MuYu_THROW_IF_FAILED(pIWICFrame->GetPixelFormat(&wpf));
	GUID tgFormat = {};

	//通过第一道转换之后获取DXGI的等价格式
	if (GetTargetPixelFormat(&wpf, &tgFormat))
	{
		stTextureFormat = GetDXGIFormatFromPixelFormat(&tgFormat);
	}

	if (DXGI_FORMAT_UNKNOWN == stTextureFormat)
	{// 不支持的图片格式 目前退出了事 
	 // 一般 在实际的引擎当中都会提供纹理格式转换工具，
	 // 图片都需要提前转换好，所以不会出现不支持的现象
		throw MuYuException(S_FALSE);
	}

	if (!InlineIsEqualGUID(wpf, tgFormat))
	{// 这个判断很重要，如果原WIC格式不是直接能转换为DXGI格式的图片时
	 // 我们需要做的就是转换图片格式为能够直接对应DXGI格式的形式
		//创建图片格式转换器
		ComPtr<IWICFormatConverter> pIConverter;
		MuYu_THROW_IF_FAILED(pIWICFactory->CreateFormatConverter(&pIConverter));

		//初始化一个图片转换器，实际也就是将图片数据进行了格式转换
		MuYu_THROW_IF_FAILED(pIConverter->Initialize(
			pIWICFrame.Get(),                // 输入原图片数据
			tgFormat,						 // 指定待转换的目标格式
			WICBitmapDitherTypeNone,         // 指定位图是否有调色板，现代都是真彩位图，不用调色板，所以为None
			NULL,                            // 指定调色板指针
			0.f,                             // 指定Alpha阀值
			WICBitmapPaletteTypeCustom       // 调色板类型，实际没有使用，所以指定为Custom
		));
		// 调用QueryInterface方法获得对象的位图数据源接口
		MuYu_THROW_IF_FAILED(pIConverter.As(&pIBMP));
	}
	else
	{
		//图片数据格式不需要转换，直接获取其位图数据源接口
		MuYu_THROW_IF_FAILED(pIWICFrame.As(&pIBMP));
	}
	//获得图片大小（单位：像素）
	MuYu_THROW_IF_FAILED(pIBMP->GetSize(&nTextureW, &nTextureH));

	//获取图片像素的位大小的BPP（Bits Per Pixel）信息，用以计算图片行数据的真实大小（单位：字节）
	ComPtr<IWICComponentInfo> pIWICmntinfo;
	MuYu_THROW_IF_FAILED(pIWICFactory->CreateComponentInfo(tgFormat, pIWICmntinfo.GetAddressOf()));

	WICComponentType type;
	MuYu_THROW_IF_FAILED(pIWICmntinfo->GetComponentType(&type));

	if (type != WICPixelFormat)
	{
		throw MuYuException(S_FALSE);
	}

	ComPtr<IWICPixelFormatInfo> pIWICPixelinfo;
	MuYu_THROW_IF_FAILED(pIWICmntinfo.As(&pIWICPixelinfo));

	// 到这里终于可以得到BPP了，这也是我看的比较吐血的地方，为了BPP居然饶了这么多环节
	MuYu_THROW_IF_FAILED(pIWICPixelinfo->GetBitsPerPixel(&nBPP));

	// 计算图片实际的行大小（单位：字节），这里使用了一个上取整除法即（A+B-1）/B ，
	// 这曾经被传说是微软的面试题,希望你已经对它了如指掌
	nPicRowPitch = (uint64_t(nTextureW) * uint64_t(nBPP) + 7u) / 8u;

}